#include "TCPSession.h"
#include "httpParser.h"
#include "common.h"
#include <set>
#include <sstream>
#include "osip_net.h"
#include "Buffer.h"
#include "multipart_parser.h"
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <chrono>
#include <iomanip>
#include <thread>

#define MAX_BUFFER_128KSZ				0x20000
#define MAX_BUFFER_4KSZ					0x1000	 //4k
#define TCPRECV_BUFLEN 4096

#ifndef WIN32
#include <iconv.h> 
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fstream>
#include <string>
#include <iostream>
#include <vector>
#include "log4z.h"

CTCPSession::CTCPSession()
{
	m_lengh = 0;
	m_fdClient = SOCKET_ERROR;
	m_chars = nullptr;
	LOGFMTI("%s", __func__);
}

CTCPSession::~CTCPSession()
{
	StopServer();
	LOGFMTI("%s", __func__);
}

int CTCPSession::StartServer(socket_t fdClient)
{
	m_chars = (char*)malloc(MAX_BUFFER_512KSZ);
	if (!m_chars) {
		LOGFMTE("new m_chars error");
		return -1;
	}
	m_fdClient = fdClient;
	// return osip_thread::Start();
	m_quit = true;
	return 0;
}

int CTCPSession::StopServer()
{
	// if (m_lxThread)
	// {
	// 	m_lxThread->End();
	// 	delete m_lxThread;
	// }
	m_quit = false;
	SAFE_FREE(m_chars);
	fdClose(m_fdClient);
	return 0;
}

static int setRecvBuf(int fd, int size) {
	int ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, sizeof(size));
	if (ret == -1) {
		printf("setsockopt errno = % d:%s\n", errno, strerror(errno));
		printf("%s (%s) %d\n", __FILE__, __FUNCTION__, __LINE__);
	}
	return ret;
}

static int setSendBuf(int fd, int size) {
	int ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&size, sizeof(size));
	if (ret == -1) {
		printf("setsockopt errno = % d:%s\n", errno, strerror(errno));
		printf("%s (%s) %d\n", __FILE__, __FUNCTION__, __LINE__);
	}
	return ret;
}

int CTCPSession::run()
{
#ifndef WIN32
	prctl(PR_SET_NAME, "httpsrv");
#endif
	int nRecvByte = 0;
	fd_set fdRead = { 0 };
	struct timeval  tv = { 0 };
	char buffer[TCPRECV_BUFLEN] = { 0 };

	setRecvBuf(m_fdClient, 256 * 1024);
	setSendBuf(m_fdClient, 256 * 1024);

	auto current_time = std::chrono::steady_clock::now();
	while (m_quit) {
		auto start_time = std::chrono::steady_clock::now();
		auto elapsed_time = std::chrono::duration_cast<std::chrono::seconds>(current_time - start_time).count();

		if (elapsed_time >= 30) {
			LOGFMTE("30 seconds no data received, exit loop");
			break;
		}

		tv.tv_sec = 0;
		FD_ZERO(&fdRead);
		tv.tv_usec = 500 * 1000;
		FD_SET(m_fdClient, &fdRead);
#ifdef WIN32
		if (select((int)m_fdClient, &fdRead, NULL, NULL, &tv) > 0) {
#else
		if (select(m_fdClient + 1, &fdRead, NULL, NULL, &tv) > 0) {
#endif
			if (FD_ISSET(m_fdClient, &fdRead)) {
				nRecvByte = recv(m_fdClient, buffer, TCPRECV_BUFLEN, 0);

				if (nRecvByte > 0) {
					OnReceive(buffer, nRecvByte);
					start_time = std::chrono::steady_clock::now();
				}
				else {
					if (nRecvByte == 0) {
						struct sockaddr_in client;
						socklen_t len = sizeof(client);
						getpeername(m_fdClient, (struct sockaddr*)&client, &len);
						LOGFMTI("Client disconnect [ IP : %s ] [ PORT : %d ]", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
						break;
					}
					else if (nRecvByte == -1) {
						if (errno == EAGAIN || errno == EWOULDBLOCK) {
							continue;
						}
						else if (errno == EINTR) {
							continue;
						}
						else {
							LOGFMTE("close fd:%d, %s, [%d] %s", m_fdClient, get_ip_prot(m_fdClient).c_str(), errno, strerror(errno));
							break;
						}
					}
				}
			}
		}
		else {
			// 在循环内部检查循环时间
			current_time = std::chrono::steady_clock::now();
		}
	}
	return 0;
}

void CTCPSession::OnReceive(const char* data, int len)
{
	sendMessage(data, len);
	//if (m_lengh + len > MAX_BUFFER_512KSZ) {
	//	m_lengh = 0;
	//}
	//memcpy(m_chars + m_lengh, data, len);
	//m_lengh += len;
	//char* ptr = m_chars;
	//printf("%s %s %d m_chars:%s\n", __FILE__, __FUNCTION__, __LINE__, ptr);
	//while (m_lengh >= sizeof(COMMNET_HEADER) && ptr)
	//{
	//	COMMNET_HEADER* pCOMMNET_HEADER = (COMMNET_HEADER*)ptr;
	//	if (pCOMMNET_HEADER)
	//	{
	//		if ((NETCMD_FLAG != pCOMMNET_HEADER->nFlag) || (NET_VERSION != pCOMMNET_HEADER->dwvsion))
	//		{
	//			ptr++;
	//			m_lengh--;
	//		}
	//		else
	//		{
	//			if (m_lengh < sizeof(COMMNET_HEADER) + pCOMMNET_HEADER->dwBufSize) {
	//				return;
	//			}
	//			if (NETCMD_EXECSQLFUNC == pCOMMNET_HEADER->dwCmd)
	//			{
	//				LOGFMTE("pCOMMNET_HEADER->dwCmd:%x pCOMMNET_HEADER->dwBufSize:%d\n", pCOMMNET_HEADER->dwCmd, pCOMMNET_HEADER->dwBufSize);
	//				//printf("%s (%s) %d\n", __FILE__, __FUNCTION__, __LINE__);
	//				const char* p = (char*)(ptr + sizeof(COMMNET_HEADER));
	//				std::string errorMsg;
	//				CJSONParse parse(p);
	//				cJSON* root = parse.GetRootItem();
	//				if (!root) {
	//					LOGFMTE("%s", p);
	//				}
	//				else {

	//				}
	//			}
	//			else if (NETCMD_RAWQUERYFUNC == pCOMMNET_HEADER->dwCmd)
	//			{
	//				const char* p = (char*)(ptr + sizeof(COMMNET_HEADER));
	//				std::string errorMsg;
	//				CJSONParse parse(p);
	//				cJSON* root = parse.GetRootItem();
	//				if (!root) {
	//					LOGFMTE("%s", p);
	//				}
	//				else {

	//				}
	//			}
	//			memmove(m_chars, m_chars + sizeof(COMMNET_HEADER) + pCOMMNET_HEADER->dwBufSize, m_lengh - sizeof(COMMNET_HEADER) - pCOMMNET_HEADER->dwBufSize);
	//			m_lengh -= sizeof(COMMNET_HEADER);
	//			m_lengh -= pCOMMNET_HEADER->dwBufSize;
	//		}
	//	}
	//	else {
	//		StopServer();
	//		LOGFMTE("非法连接");
	//		m_lengh = 0;
	//		return;
	//	}
	//}
}

int CTCPSession::sendMessage(const char* data, int len)
{
	// LOGFMTE("----  %s",data);
	//LOGFMTI("---- send data len: %d", len);
	if (!data || len <= 0) {
		return -1;
	}
	if (-1 == m_fdClient) {
		return 0;
	}

	int dwRepeate = 0;
	int dwByte, dwWrite = 0;

	do {
#ifdef WIN32
		dwByte = send(m_fdClient, data + dwWrite, len, 0);
		if (dwByte < 0) {
			if ((WSAEWOULDBLOCK == WSAGetLastError()) && (dwRepeate++ < 3)) {
				Sleep(20);
				continue;
			}
			return XX_ERR_NONE;
		}
#else
		dwByte = send(m_fdClient, data + dwWrite, len, MSG_NOSIGNAL);
		if (dwByte <= 0) {
			// if ((EAGAIN == errno) && (dwRepeate++ < 30)) {
			if ((EAGAIN == errno)) {
				LOGFMTE("Error1(%d): %s", errno, strerror(errno));
				usleep(10000);
				continue;
			}
			LOGFMTI("----------------------");
			LOGFMTE("Error2(%d): %s", errno, strerror(errno));
			return XX_ERR_NONE;
		}
#endif
		len -= dwByte;
		dwWrite += dwByte;
	} while (len > 0);
	//LOGFMTI("=======================");
	return dwWrite;
}

void CTCPSession::sendJson(int cmd, cJSON * json) {
	char* ptr = cJSON_Print(json);
	COMMNET_HEADER* tCOMMNET_HEADER = new COMMNET_HEADER;
	tCOMMNET_HEADER->nFlag = NETCMD_FLAG;
	tCOMMNET_HEADER->dwCmd = cmd;
	tCOMMNET_HEADER->dwvsion = NET_VERSION;
	tCOMMNET_HEADER->dwBufSize = (unsigned int)strlen(ptr);

	sendMessage((char*)tCOMMNET_HEADER, sizeof(COMMNET_HEADER));
	sendMessage((char*)ptr, (int)strlen(ptr));

	delete tCOMMNET_HEADER;
	cJSON_Delete(json);
	SAFE_FREE(ptr);
}